🎖️GitЯра🎖️
Node / meshtastic / Meshtastic-Android / files / core / ui / src / commonMain / kotlin / org / meshtastic / core / ui / component / MeshtasticNavigationSuite.kt
Displaying Raw • Download
core/ui/src/commonMain/kotlin/org/meshtastic/core/ui/component/MeshtasticNavigationSuite.kt 1390a3cd4f7bc55a37433d1d868e65c01678eb31 (1390a3cd) Text, 10.04 KB
T8b949e/*
* Copyright (c) 2025-2026 Meshtastic LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
Tff7b72package T7ee787org.meshtastic.core.ui.component
Tff7b72import T7ee787androidx.compose.animation.AnimatedVisibility
Tff7b72import T7ee787androidx.compose.animation.Crossfade
Tff7b72import T7ee787androidx.compose.animation.fadeIn
Tff7b72import T7ee787androidx.compose.animation.fadeOut
Tff7b72import T7ee787androidx.compose.animation.scaleIn
Tff7b72import T7ee787androidx.compose.animation.scaleOut
Tff7b72import T7ee787androidx.compose.foundation.layout.Row
Tff7b72import T7ee787androidx.compose.material3.Badge
Tff7b72import T7ee787androidx.compose.material3.BadgedBox
Tff7b72import T7ee787androidx.compose.material3.ExperimentalMaterial3Api
Tff7b72import T7ee787androidx.compose.material3.Icon
Tff7b72import T7ee787androidx.compose.material3.LocalContentColor
Tff7b72import T7ee787androidx.compose.material3.MaterialTheme.colorScheme
Tff7b72import T7ee787androidx.compose.material3.PlainTooltip
Tff7b72import T7ee787androidx.compose.material3.Text
Tff7b72import T7ee787androidx.compose.material3.TooltipAnchorPosition
Tff7b72import T7ee787androidx.compose.material3.TooltipBox
Tff7b72import T7ee787androidx.compose.material3.TooltipDefaults
Tff7b72import T7ee787androidx.compose.material3.adaptive.currentWindowAdaptiveInfo
Tff7b72import T7ee787androidx.compose.material3.adaptive.navigationsuite.NavigationSuiteScaffold
Tff7b72import T7ee787androidx.compose.material3.adaptive.navigationsuite.NavigationSuiteScaffoldDefaults
Tff7b72import T7ee787androidx.compose.material3.adaptive.navigationsuite.NavigationSuiteType
Tff7b72import T7ee787androidx.compose.material3.rememberTooltipState
Tff7b72import T7ee787androidx.compose.runtime.Composable
Tff7b72import T7ee787androidx.compose.runtime.getValue
Tff7b72import T7ee787androidx.compose.runtime.mutableIntStateOf
Tff7b72import T7ee787androidx.compose.runtime.remember
Tff7b72import T7ee787androidx.compose.runtime.setValue
Tff7b72import T7ee787androidx.compose.ui.Modifier
Tff7b72import T7ee787androidx.lifecycle.compose.collectAsStateWithLifecycle
Tff7b72import T7ee787org.jetbrains.compose.resources.stringResource
Tff7b72import T7ee787org.jetbrains.compose.resources.vectorResource
Tff7b72import T7ee787org.meshtastic.core.model.ConnectionState
Tff7b72import T7ee787org.meshtastic.core.model.DeviceType
Tff7b72import T7ee787org.meshtastic.core.navigation.ContactsRoute
Tff7b72import T7ee787org.meshtastic.core.navigation.MultiBackstack
Tff7b72import T7ee787org.meshtastic.core.navigation.NodesRoute
Tff7b72import T7ee787org.meshtastic.core.navigation.TopLevelDestination
Tff7b72import T7ee787org.meshtastic.core.resources.Res
Tff7b72import T7ee787org.meshtastic.core.resources.connected
Tff7b72import T7ee787org.meshtastic.core.resources.connecting
Tff7b72import T7ee787org.meshtastic.core.resources.device_sleeping
Tff7b72import T7ee787org.meshtastic.core.resources.disconnected
Tff7b72import T7ee787org.meshtastic.core.ui.navigation.icon
Tff7b72import T7ee787org.meshtastic.core.ui.viewmodel.UIViewModel
T8b949e/**
* Shared adaptive navigation shell using [NavigationSuiteScaffold].
*
* This implementation uses the [MultiBackstack] state holder to manage independent histories for each tab, aligning
* with Navigation 3 best practices for state preservation during tab switching.
*/
Tf0883e@OptInTb4b4b4(Te6edf3ExperimentalMaterial3ApiTff7b72::Te6edf3classTb4b4b4)
Tf0883e@Composable
Tff7b72fun Td2a8ffMeshtasticNavigationSuiteTb4b4b4(
Te6edf3multiBackstackTb4b4b4: Te6edf3MultiBackstackTb4b4b4,
Te6edf3uiViewModelTb4b4b4: Te6edf3UIViewModelTb4b4b4,
Te6edf3modifierTb4b4b4: Te6edf3Modifier Tff7b72= Te6edf3ModifierTb4b4b4,
Te6edf3contentTb4b4b4: Tf0883e@Composable Tb4b4b4(Tb4b4b4) Tff7b72-Tff7b72> Tffa657UnitTb4b4b4,
Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3connectionState Tff7b72by Te6edf3uiViewModelTb4b4b4.Te6edf3connectionStateTb4b4b4.Te6edf3collectAsStateWithLifecycleTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3unreadMessageCount Tff7b72by Te6edf3uiViewModelTb4b4b4.Te6edf3unreadMessageCountTb4b4b4.Te6edf3collectAsStateWithLifecycleTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3selectedDevice Tff7b72by Te6edf3uiViewModelTb4b4b4.Te6edf3currentDeviceAddressFlowTb4b4b4.Te6edf3collectAsStateWithLifecycleTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3adaptiveInfo Tff7b72= Te6edf3currentWindowAdaptiveInfoTb4b4b4(Te6edf3supportLargeAndXLargeWidth Tff7b72= Tff7b72trueTb4b4b4)
Tff7b72val Te6edf3currentTabRoute Tff7b72= Te6edf3multiBackstackTb4b4b4.Te6edf3currentTabRoute
Tff7b72val Te6edf3topLevelDestination Tff7b72= Te6edf3TopLevelDestinationTb4b4b4.Te6edf3fromNavKeyTb4b4b4(Te6edf3currentTabRouteTb4b4b4)
Tff7b72val Te6edf3layoutType Tff7b72= Te6edf3NavigationSuiteScaffoldDefaultsTb4b4b4.Te6edf3calculateFromAdaptiveInfoTb4b4b4(Te6edf3adaptiveInfoTb4b4b4)Tb4b4b4.Te6edf3coerceNavigationTypeTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3showLabels Tff7b72= Te6edf3layoutType Tff7b72=Tff7b72= Te6edf3NavigationSuiteTypeTb4b4b4.Te6edf3NavigationRail
Te6edf3NavigationSuiteScaffoldTb4b4b4(
Te6edf3modifier Tff7b72= Te6edf3modifierTb4b4b4,
Te6edf3layoutType Tff7b72= Te6edf3layoutTypeTb4b4b4,
Te6edf3navigationSuiteItems Tff7b72= Tb4b4b4{
Te6edf3TopLevelDestinationTb4b4b4.Te6edf3entriesTb4b4b4.Te6edf3forEach Tb4b4b4{ Te6edf3destination Tff7b72-Tff7b72>
Tff7b72val Te6edf3isSelected Tff7b72= Te6edf3destination Tff7b72=Tff7b72= Te6edf3topLevelDestination
Te6edf3itemTb4b4b4(
Te6edf3selected Tff7b72= Te6edf3isSelectedTb4b4b4,
Te6edf3onClick Tff7b72= Tb4b4b4{ Te6edf3handleNavigationTb4b4b4(Te6edf3destinationTb4b4b4, Te6edf3topLevelDestinationTb4b4b4, Te6edf3multiBackstackTb4b4b4, Te6edf3uiViewModelTb4b4b4) Tb4b4b4}Tb4b4b4,
Te6edf3icon Tff7b72= Tb4b4b4{
Te6edf3NavigationIconContentTb4b4b4(
Te6edf3destination Tff7b72= Te6edf3destinationTb4b4b4,
Te6edf3isSelected Tff7b72= Te6edf3isSelectedTb4b4b4,
Te6edf3connectionState Tff7b72= Te6edf3connectionStateTb4b4b4,
Te6edf3unreadMessageCount Tff7b72= Te6edf3unreadMessageCountTb4b4b4,
Te6edf3selectedDevice Tff7b72= Te6edf3selectedDeviceTb4b4b4,
Te6edf3uiViewModel Tff7b72= Te6edf3uiViewModelTb4b4b4,
Tb4b4b4)
Tb4b4b4}Tb4b4b4,
Te6edf3label Tff7b72=
Tff7b72if Tb4b4b4(Te6edf3showLabelsTb4b4b4) Tb4b4b4{
Tb4b4b4{ Te6edf3TextTb4b4b4(Te6edf3stringResourceTb4b4b4(Te6edf3destinationTb4b4b4.Te6edf3labelTb4b4b4)Tb4b4b4) Tb4b4b4}
Tb4b4b4} Tff7b72else Tb4b4b4{
Tff7b72null
Tb4b4b4}Tb4b4b4,
Tb4b4b4)
Tb4b4b4}
Tb4b4b4}Tb4b4b4,
Tb4b4b4) Tb4b4b4{
Te6edf3Row Tb4b4b4{ Te6edf3contentTb4b4b4(Tb4b4b4) Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
T8b949e/**
* Caps [NavigationSuiteType] so that expanded/extra-large widths still use a NavigationRail instead of promoting to a
* permanent NavigationDrawer.
*/
Tff7b72private Tff7b72fun Te6edf3NavigationSuiteTypeTb4b4b4.Td2a8ffcoerceNavigationTypeTb4b4b4(Tb4b4b4)Tb4b4b4: Te6edf3NavigationSuiteType Tff7b72= Tff7b72when Tb4b4b4(Tff7b72thisTb4b4b4) Tb4b4b4{
Te6edf3NavigationSuiteTypeTb4b4b4.Te6edf3NavigationDrawer Tff7b72-Tff7b72> Te6edf3NavigationSuiteTypeTb4b4b4.Te6edf3NavigationRail
Tff7b72else Tff7b72-Tff7b72> Tff7b72this
Tb4b4b4}
Tff7b72private Tff7b72fun Td2a8ffhandleNavigationTb4b4b4(
Te6edf3destinationTb4b4b4: Te6edf3TopLevelDestinationTb4b4b4,
Te6edf3topLevelDestinationTb4b4b4: Te6edf3TopLevelDestination?Tb4b4b4,
Te6edf3multiBackstackTb4b4b4: Te6edf3MultiBackstackTb4b4b4,
Te6edf3uiViewModelTb4b4b4: Te6edf3UIViewModelTb4b4b4,
Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3isRepress Tff7b72= Te6edf3destination Tff7b72=Tff7b72= Te6edf3topLevelDestination
Tff7b72if Tb4b4b4(Te6edf3isRepressTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3currentKey Tff7b72= Te6edf3multiBackstackTb4b4b4.Te6edf3activeBackStackTb4b4b4.Te6edf3lastOrNullTb4b4b4(Tb4b4b4)
Tff7b72when Tb4b4b4(Te6edf3destinationTb4b4b4) Tb4b4b4{
Te6edf3TopLevelDestinationTb4b4b4.Te6edf3Nodes Tff7b72-Tff7b72> Tb4b4b4{
Tff7b72val Te6edf3onNodesList Tff7b72= Te6edf3currentKey Tff7b72is Te6edf3NodesRouteTb4b4b4.Te6edf3NodesGraph Tff7b72|Tff7b72| Te6edf3currentKey Tff7b72is Te6edf3NodesRouteTb4b4b4.Te6edf3Nodes
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3onNodesListTb4b4b4) Tb4b4b4{
Te6edf3multiBackstackTb4b4b4.Te6edf3navigateTopLevelTb4b4b4(Te6edf3destinationTb4b4b4.Te6edf3routeTb4b4b4)
Tb4b4b4} Tff7b72else Tb4b4b4{
Te6edf3uiViewModelTb4b4b4.Te6edf3emitScrollToTopEventTb4b4b4(Te6edf3ScrollToTopEventTb4b4b4.Te6edf3NodesTabPressedTb4b4b4)
Tb4b4b4}
Tb4b4b4}
Te6edf3TopLevelDestinationTb4b4b4.Te6edf3Conversations Tff7b72-Tff7b72> Tb4b4b4{
Tff7b72val Te6edf3onConversationsList Tff7b72=
Te6edf3currentKey Tff7b72is Te6edf3ContactsRouteTb4b4b4.Te6edf3ContactsGraph Tff7b72|Tff7b72| Te6edf3currentKey Tff7b72is Te6edf3ContactsRouteTb4b4b4.Te6edf3Contacts
Tff7b72if Tb4b4b4(Tff7b72!Te6edf3onConversationsListTb4b4b4) Tb4b4b4{
Te6edf3multiBackstackTb4b4b4.Te6edf3navigateTopLevelTb4b4b4(Te6edf3destinationTb4b4b4.Te6edf3routeTb4b4b4)
Tb4b4b4} Tff7b72else Tb4b4b4{
Te6edf3uiViewModelTb4b4b4.Te6edf3emitScrollToTopEventTb4b4b4(Te6edf3ScrollToTopEventTb4b4b4.Te6edf3ConversationsTabPressedTb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tff7b72else Tff7b72-Tff7b72> Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3currentKey Tff7b72!Tff7b72= Te6edf3destinationTb4b4b4.Te6edf3routeTb4b4b4) Tb4b4b4{
Te6edf3multiBackstackTb4b4b4.Te6edf3navigateTopLevelTb4b4b4(Te6edf3destinationTb4b4b4.Te6edf3routeTb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tb4b4b4} Tff7b72else Tb4b4b4{
Te6edf3multiBackstackTb4b4b4.Te6edf3navigateTopLevelTb4b4b4(Te6edf3destinationTb4b4b4.Te6edf3routeTb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tf0883e@OptInTb4b4b4(Te6edf3ExperimentalMaterial3ApiTff7b72::Te6edf3classTb4b4b4)
Tf0883e@Composable
Tff7b72private Tff7b72fun Td2a8ffNavigationIconContentTb4b4b4(
Te6edf3destinationTb4b4b4: Te6edf3TopLevelDestinationTb4b4b4,
Te6edf3isSelectedTb4b4b4: Tffa657BooleanTb4b4b4,
Te6edf3connectionStateTb4b4b4: Te6edf3ConnectionStateTb4b4b4,
Te6edf3unreadMessageCountTb4b4b4: Tffa657IntTb4b4b4,
Te6edf3selectedDeviceTb4b4b4: Tffa657String?Tb4b4b4,
Te6edf3uiViewModelTb4b4b4: Te6edf3UIViewModelTb4b4b4,
Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3isConnectionsRoute Tff7b72= Te6edf3destination Tff7b72=Tff7b72= Te6edf3TopLevelDestinationTb4b4b4.Te6edf3Connections
Te6edf3TooltipBoxTb4b4b4(
Te6edf3positionProvider Tff7b72= Te6edf3TooltipDefaultsTb4b4b4.Te6edf3rememberTooltipPositionProviderTb4b4b4(Te6edf3TooltipAnchorPositionTb4b4b4.Te6edf3AboveTb4b4b4)Tb4b4b4,
Te6edf3tooltip Tff7b72= Tb4b4b4{
Te6edf3PlainTooltip Tb4b4b4{
Te6edf3TextTb4b4b4(
Tff7b72if Tb4b4b4(Te6edf3isConnectionsRouteTb4b4b4) Tb4b4b4{
Tff7b72when Tb4b4b4(Te6edf3connectionStateTb4b4b4) Tb4b4b4{
Te6edf3ConnectionStateTb4b4b4.Te6edf3Connected Tff7b72-Tff7b72> Te6edf3stringResourceTb4b4b4(Te6edf3ResTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3connectedTb4b4b4)
Te6edf3ConnectionStateTb4b4b4.Te6edf3Connecting Tff7b72-Tff7b72> Te6edf3stringResourceTb4b4b4(Te6edf3ResTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3connectingTb4b4b4)
Te6edf3ConnectionStateTb4b4b4.Te6edf3DeviceSleep Tff7b72-Tff7b72> Te6edf3stringResourceTb4b4b4(Te6edf3ResTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3device_sleepingTb4b4b4)
Te6edf3ConnectionStateTb4b4b4.Te6edf3Disconnected Tff7b72-Tff7b72> Te6edf3stringResourceTb4b4b4(Te6edf3ResTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3disconnectedTb4b4b4)
Tb4b4b4}
Tb4b4b4} Tff7b72else Tb4b4b4{
Te6edf3stringResourceTb4b4b4(Te6edf3destinationTb4b4b4.Te6edf3labelTb4b4b4)
Tb4b4b4}Tb4b4b4,
Tb4b4b4)
Tb4b4b4}
Tb4b4b4}Tb4b4b4,
Te6edf3state Tff7b72= Te6edf3rememberTooltipStateTb4b4b4(Tb4b4b4)Tb4b4b4,
Tb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3isConnectionsRouteTb4b4b4) Tb4b4b4{
Te6edf3AnimatedConnectionsNavIconTb4b4b4(
Te6edf3connectionState Tff7b72= Te6edf3connectionStateTb4b4b4,
Te6edf3deviceType Tff7b72= Te6edf3DeviceTypeTb4b4b4.Te6edf3fromAddressTb4b4b4(Te6edf3selectedDevice Tff7b72?: Ta5d6ff"Ta5d6ffNoDeviceTa5d6ff"Tb4b4b4)Tb4b4b4,
Te6edf3meshActivityFlow Tff7b72= Te6edf3uiViewModelTb4b4b4.Te6edf3meshActivityTb4b4b4,
Tb4b4b4)
Tb4b4b4} Tff7b72else Tb4b4b4{
Te6edf3BadgedBoxTb4b4b4(
Te6edf3badge Tff7b72= Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3destination Tff7b72=Tff7b72= Te6edf3TopLevelDestinationTb4b4b4.Te6edf3ConversationsTb4b4b4) Tb4b4b4{
Tff7b72var Te6edf3lastNonZeroCount Tff7b72by Te6edf3remember Tb4b4b4{ Te6edf3mutableIntStateOfTb4b4b4(Te6edf3unreadMessageCountTb4b4b4) Tb4b4b4}
Tff7b72if Tb4b4b4(Te6edf3unreadMessageCount Tff7b72> T79c0ff0Tb4b4b4) Tb4b4b4{
Te6edf3lastNonZeroCount Tff7b72= Te6edf3unreadMessageCount
Tb4b4b4}
Te6edf3AnimatedVisibilityTb4b4b4(
Te6edf3visible Tff7b72= Te6edf3unreadMessageCount Tff7b72> T79c0ff0Tb4b4b4,
Te6edf3enter Tff7b72= Te6edf3scaleInTb4b4b4(Tb4b4b4) Tff7b72+ Te6edf3fadeInTb4b4b4(Tb4b4b4)Tb4b4b4,
Te6edf3exit Tff7b72= Te6edf3scaleOutTb4b4b4(Tb4b4b4) Tff7b72+ Te6edf3fadeOutTb4b4b4(Tb4b4b4)Tb4b4b4,
Tb4b4b4) Tb4b4b4{
Te6edf3Badge Tb4b4b4{ Te6edf3TextTb4b4b4(Te6edf3lastNonZeroCountTb4b4b4.Te6edf3toStringTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}Tb4b4b4,
Tb4b4b4) Tb4b4b4{
Te6edf3CrossfadeTb4b4b4(Te6edf3isSelectedTb4b4b4, Te6edf3label Tff7b72= Ta5d6ff"Ta5d6ffBottomBarIconTa5d6ff"Tb4b4b4) Tb4b4b4{ Te6edf3isSelectedState Tff7b72-Tff7b72>
Te6edf3IconTb4b4b4(
Te6edf3imageVector Tff7b72= Te6edf3vectorResourceTb4b4b4(Te6edf3destinationTb4b4b4.Te6edf3iconTb4b4b4)Tb4b4b4,
Te6edf3contentDescription Tff7b72= Te6edf3stringResourceTb4b4b4(Te6edf3destinationTb4b4b4.Te6edf3labelTb4b4b4)Tb4b4b4,
Te6edf3tint Tff7b72= Tff7b72if Tb4b4b4(Te6edf3isSelectedStateTb4b4b4) Te6edf3colorSchemeTb4b4b4.Te6edf3primary Tff7b72else Te6edf3LocalContentColorTb4b4b4.Te6edf3currentTb4b4b4,
Tb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Served by rngit 1.5.0 - Generated in 0.08s